package com.sinodata.ns.file;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;


public class HttpPostUtil {
    private URL url;
    private HttpURLConnection conn;
    private String boundary = "--------httppost123";
    private Map textParams = new HashMap();
    private Map fileparams = new HashMap();
    private boolean isMulti;

    public HttpPostUtil(String url) throws Exception {
        this.url = new URL(url);
    }

    public HttpPostUtil(String protocol, String host, int port, String file)
        throws Exception {
        this.url = new URL(protocol, host, port, file);
    }

    //重新设置要请求的服务器地址，即上传文件的地址。    
    public void setUrl(String url) throws Exception {
        this.url = new URL(url);
    }

    //增加一个普通字符串数据到form表单数据中    
    public void addTextParameter(String name, String value) {
        textParams.put(name, value);
    }

    //增加一个文件到form表单数据中    
    public void addFileParameter(String name, File value) {
        fileparams.put(name, value);
    }

    // 清空所有已添加的form表单数据    
    public void clearAllParameters() {
        textParams.clear();
        fileparams.clear();
    }

    // 发送数据到服务器，返回一个字节包含服务器的返回结果的数组    
    public byte[] send() throws Exception {
        initConnection();

        try {
            conn.connect();
        } catch (SocketTimeoutException e) {
            // something    
            throw new RuntimeException();
        }

        DataOutputStream ds = new DataOutputStream(conn.getOutputStream());
        writeFileParams(ds);
        writeStringParams(ds);
        paramsEnd(ds);

        if (ds != null) {
            try {
                ds.flush();
                ds.close();
            } catch (Exception ex) {
                ex.printStackTrace(System.out);
            }
        }

        InputStream in = conn.getInputStream();
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int b;

        while ((b = in.read()) != -1) {
            out.write(b);
        }

        conn.disconnect();

        return out.toByteArray();
    }

    //文件上传的connection的一些必须设置    
    private void initConnection() throws Exception {
        this.isMulti = !this.fileparams.isEmpty();

        boundary = java.util.UUID.randomUUID().toString();

        conn = (HttpURLConnection) this.url.openConnection();
        conn.setDoOutput(true);
        conn.setUseCaches(false);
        conn.setConnectTimeout(60000); //连接超时为10秒    
        conn.setRequestMethod("POST");
        conn.setRequestProperty("User-Agent",
            "Mozilla/4.0 (compatible; MSIE 6.0; Windows 2000)");

        if (!isMulti) {
            conn.setRequestProperty("Content-Type",
                "application/x-www-form-urlencoded");
        } else {
            conn.setRequestProperty("Content-Type",
                "multipart/form-data; boundary=" + boundary);
        }
    }

    //普通字符串数据    
    private void writeStringParams(DataOutputStream ds)
        throws Exception {
        if (this.isMulti) {
            Iterator keys = textParams.keySet().iterator();

            while (keys.hasNext()) {
                String name = (String) keys.next();

                String value = encode((String) textParams.get(name));

                ds.writeBytes("--" + boundary + "\r\n");
                ds.writeBytes("Content-Disposition: form-data; name=\"" + name +
                    "\"\r\n");
                ds.writeBytes("\r\n");
                ds.writeBytes(value + "\r\n");
            }
        } else {
            StringBuffer params = new StringBuffer();

            Iterator it = textParams.entrySet().iterator();

            while (it.hasNext()) {
                Entry element = (Entry) it.next();
                params.append(element.getKey());
                params.append("=");
                params.append(encode((String)element.getValue()));
                params.append("&");
            }
            
            ds.writeBytes(params.toString());
        }
    }

    //文件数据    
    private void writeFileParams(DataOutputStream ds) throws Exception {
        Iterator keys = fileparams.keySet().iterator();

        while (keys.hasNext()) {
            String name = (String) keys.next();
            File value = (File) fileparams.get(name);
            ds.writeBytes("--" + boundary + "\r\n");
            ds.writeBytes("Content-Disposition: form-data; name=\"" + name +
                "\"; filename=\"" + encode(value.getName()) + "\"\r\n");
            ds.writeBytes("Content-Type: " + getContentType(value) + "\r\n");
            ds.writeBytes("\r\n");
            ds.write(getBytes(value));
            ds.writeBytes("\r\n");
        }
    }

    //获取文件的上传类型，图片格式为image/png,image/jpg等。非图片为application/octet-stream    
    private String getContentType(File f) throws Exception {
        //      return "application/octet-stream";   // 此行不再细分是否为图片，全部作为application/octet-stream 类型    

        /*ImageInputStream imagein = ImageIO.createImageInputStream(f);

        if (imagein == null) {
            return "application/octet-stream";
        }

        Iterator it = ImageIO.getImageReaders(imagein);

        if (!it.hasNext()) {
            imagein.close();

            return "application/octet-stream";
        }

        imagein.close();

        return "image/" +
        ((ImageReader) it.next()).getFormatName().toLowerCase(); //将FormatName返回的值转换成小写，默认为大写
        */
        return "application/octet-stream";
    }

    //把文件转换成字节数组    
    private byte[] getBytes(File f) throws Exception {
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(f));

        byte[] result = new byte[in.available()];

        in.read(result);

        in.close();

        return result;
    }

    //添加结尾数据    
    private void paramsEnd(DataOutputStream ds) throws Exception {
        ds.writeBytes("--" + boundary + "--" + "\r\n");
        ds.writeBytes("\r\n");
    }

    // 对包含中文的字符串进行转码，此为UTF-8。服务器那边要进行一次解码    
    private String encode(String value) throws Exception {
        // return URLEncoder.encode(value, "ISO-8859-1");
        return new String(value.getBytes("UTF-8"), "ISO-8859-1");
    }

    public static void main(String[] args) throws Exception {
        HttpPostUtil u = new HttpPostUtil(
                "http://localhost:8080/ns/app/fileupload.do?method=upload");

        u.addFileParameter("nffile", new File("D:\\test.jpg"));
        u.addTextParameter("userid", "EQVsufoHkwnclHaLPnLO");
        u.addTextParameter("qu",
            "时间: 2011-07-06 星期三 14:27:38 (RSA)(封装) (文件) pdi-open-src-3.1.0-826.rar");

        byte[] b = u.send();
        String result = new String(b);
        System.out.println(result);
    }
}
